﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace PIM_ATE
{
    sealed class JcPIMForDesktop : JcPIMRunner
    {
        const string logLF = "";
        TcpClient m_tcp;
        Dictionary<string, JcPIMInstrumentInfo> m_devices;
        ManualResetEvent m_mre = new ManualResetEvent(false);
        List<string> m_send_list = new List<string>();
        string m_read_buf;
        byte[] m_byte_buf = new byte[256];
        List<JcPIMDataResults> m_pim_resultLists = new List<JcPIMDataResults>();
        JcPIMDataSettings m_pim_settings;
        rflight.ClsRfPIMforDesktopCom m_RFCom;

        public JcPIMForDesktop(string ip, Instrument type)
        {
            m_devices = new Dictionary<string, JcPIMInstrumentInfo>();
            m_devices.Add("DEFAULT", new JcPIMInstrumentInfo(true, "DEFAULT", ip, type));
        }

        public JcPIMForDesktop(Dictionary<string, JcPIMInstrumentInfo> devices)
        {
            m_devices = devices;
        }

        public override void start_settings(JcPIMDataSettings settings)
        {
            settings.InstrumentType = m_devices[settings.Band_Name].instrType;
            m_pim_settings = settings;

            m_RFCom = null;
            if (m_pim_settings.Band_Name.Contains("Rflight"))
            {
                m_RFCom = new rflight.ClsRfPIMforDesktopCom(m_devices);
                m_RFCom.start_settings(settings);
                m_RFCom.evt_show_error_handle += this.On_evt_show_error_handle;
                m_RFCom.evt_show_log_handle += this.On_evt_show_log_handle;
                m_RFCom.evt_complete_test_handle += this.On_evt_complete_test_handle;
                m_RFCom.evt_get_point_handle += this.On_evt_get_point_handle;
                return;
            }

            string cmd = "";
            string crlf = "\r\n";
            m_send_list.Clear();
            if (settings.Mode == ImMode.Freq)
                cmd = "set:sweep 0" + crlf;
            else
                cmd = "set:sweep 1" + crlf;
            m_send_list.Add(cmd);

            cmd = "set:order " + ((int)settings.Order).ToString() + crlf;
            m_send_list.Add(cmd);

            if (settings.InstrumentType == Instrument.DESKTOP_FOR_2REV)
            {
                if (settings.Port_TX1 == 0 || settings.Port_TX1 == 1)
                {//双反射只能使用2口  set:type 命令会真实切换一二口  ，不论底层软件是否开启替换功能switchMode=1 
                    cmd = "set:type " + settings.Port_TX1.ToString() + crlf;
                    m_send_list.Add(cmd);
                }
            }
            else if (settings.InstrumentType == Instrument.DESKTOP_FOR_4REV ||
                     settings.InstrumentType == Instrument.DESKTOP_FOR_6REV ||
                     settings.InstrumentType == Instrument.DESKTOP_FOR_PORT)
            {//set:port   可使用替换功能，依据底层变更端口
                cmd = "set:port " + settings.Port_TX1.ToString() + crlf;
                m_send_list.Add(cmd);
            }
            else if (settings.InstrumentType == Instrument.DESKTOP_FOR_1REV)
            { }
            else
            {
                if (settings.Schema == ImSchema.FWD)
                    cmd = "set:type 0" + crlf;
                else
                    cmd = "set:type 1" + crlf;
                m_send_list.Add(cmd);
            }

            if (settings.Unit == ImUnit.dBc)
                cmd = "set:unit 0" + crlf;
            else
                cmd = "set:unit 1" + crlf;
            m_send_list.Add(cmd);

            cmd = "set:power " + settings.TX1.ToString() + crlf;
            m_send_list.Add(cmd);

            if (settings.F1s > 0)
            {
                cmd = "set:F1S " + settings.F1s.ToString() + crlf;
                m_send_list.Add(cmd);
            }
            if (settings.F1e > 0)
            {
                cmd = "set:F1E " + settings.F1e.ToString() + crlf;
                m_send_list.Add(cmd);
            }
            if (settings.F2s > 0)
            {
                cmd = "set:F2S " + settings.F2s.ToString() + crlf;
                m_send_list.Add(cmd);
            }
            if (settings.F2e > 0)
            {
                cmd = "set:F2E " + settings.F2e.ToString() + crlf;
                m_send_list.Add(cmd);
            }

            if (settings.Mode == ImMode.Freq)
            {
                if (settings.Step1 > 0)
                {
                    cmd = "set:step1 " + settings.Step1.ToString() + crlf;
                    m_send_list.Add(cmd);
                }

                if (settings.Step2 > 0)
                {
                    cmd = "set:step2 " + settings.Step2.ToString() + crlf;
                    m_send_list.Add(cmd);
                }
            }
            else
            {
                decimal time = Math.Round((decimal)settings.Time / 60, 1);
                if (settings.Time > 0)
                {
                    cmd = "set:times " + time.ToString() + crlf;
                    m_send_list.Add(cmd);
                }
                else
                {
                    cmd = "set:times " + "0.1" + crlf;
                    m_send_list.Add(cmd);
                }
            }
        }

        public override void start_test()
        {
            if (m_pim_settings.Band_Name.Contains("Rflight") && m_RFCom != null)
            {
                m_RFCom.start_test();
                return;
            }

            m_pim_resultLists.Clear();
            connect_server(m_pim_settings.Band_Name);
        }

        public override void stop_test()
        {
            m_read_buf = "";
            byte[] b = Encoding.ASCII.GetBytes("EXEC:STOP\r\n");
            m_tcp.GetStream().Write(b, 0, b.Length);
        }

        void connect_server(string connect_name = "DEFAULT")
        {
            m_tcp = new TcpClient();
            m_tcp.BeginConnect(IPAddress.Parse(m_devices[connect_name].instrAddress), 6307,
                                    new AsyncCallback(connect_callback), null);
            evt_show_msg("connect: start" + logLF, MSG_TYPE.LOG_NET);
        }

        void connect_callback(IAsyncResult ir)
        {
            try
            {
                m_tcp.EndConnect(ir);
                evt_show_msg("connect: success" + logLF, MSG_TYPE.LOG_NET);
                evt_clear_flag();
                if (m_send_list.Count > 0)
                    write_settings();
                else
                    write_exec();
            }
            catch (Exception ex)
            {
                evt_show_msg("connect-Error: " + ex.Message + logLF, MSG_TYPE.ERROR_NET);
            }
        }

        void write_settings()
        {
            if (m_send_list.Count == 0)
                return;
            byte[] b = Encoding.ASCII.GetBytes(m_send_list[0]);
            m_tcp.GetStream().BeginWrite(b, 0, b.Length, new AsyncCallback(write_settings_callback), 0);
        }

        void write_exec()
        {
            m_read_buf = "";
            byte[] b = Encoding.ASCII.GetBytes("EXEC:START\r\n");
            m_tcp.GetStream().BeginWrite(b, 0, b.Length, new AsyncCallback(write_exec_callback), null);
        }

        void write_exec_callback(IAsyncResult ir)
        {
            try
            {
                m_tcp.GetStream().EndWrite(ir);
                evt_show_msg("send: EXEC:START" + logLF, MSG_TYPE.LOG_NET);
                m_tcp.GetStream().BeginRead(m_byte_buf, 0, 256, new AsyncCallback(read_exec_callback), 0);
            }
            catch (Exception ex)
            {
                evt_show_msg("send-Error: " + ex.Message + logLF, MSG_TYPE.ERROR_NET);
            }
        }

        void read_exec_callback(IAsyncResult ir)
        {
            int num = (int)ir.AsyncState;
            int ret = m_tcp.GetStream().EndRead(ir);
            if (ret == 0)
            {
                evt_show_msg("read-Error: remote server close" + logLF, MSG_TYPE.ERROR_NET);
                return;
            }
            string temp_recv = Encoding.ASCII.GetString(m_byte_buf, 0, ret);
            m_read_buf += temp_recv;
            while (true)
            {
                int n = m_read_buf.IndexOf("\r\n");
                if (n >= 0)
                {
                    string val = m_read_buf.Substring(0, n + 2);
                    evt_show_msg("read: " + val + logLF, MSG_TYPE.LOG_NET);
                    if (val.Contains("ERR"))
                    {
                        evt_show_msg("exec-Error: " + val + logLF, MSG_TYPE.ERROR_TEST);
                        return;
                    }
                    else if (val.Contains("PIM END"))
                    {
                        evt_show_msg("exec: complete" + logLF, MSG_TYPE.LOG_TEST);
                        evt_complete_test(m_pim_resultLists, null);
                        return;
                    }
                    else if (val.Contains("PIM START"))
                    {
                        m_read_buf = m_read_buf.Remove(0, n + 2);
                        evt_show_msg("exec: start" + logLF, MSG_TYPE.LOG_TEST);
                        break;
                    }
                    JcPIMDataResults val_entry = exec_unpack(val);
                    if (val_entry == null)
                    {
                        evt_show_msg("exec-unpack-Error: " + val + logLF, MSG_TYPE.ERROR_TEST);
                        return;
                    }
                    evt_update_ui(val_entry, null);
                    m_read_buf = m_read_buf.Remove(0, n + 2);
                }
                else
                {
                    break;
                }
            }
            num++;
            m_tcp.GetStream().BeginRead(m_byte_buf, 0, 256, new AsyncCallback(read_exec_callback), num);
        }

        void write_settings_callback(IAsyncResult ir)
        {
            try
            {
                int num = (int)ir.AsyncState;
                m_tcp.GetStream().EndWrite(ir);

                evt_show_msg("send: " + m_send_list[num] + logLF, MSG_TYPE.LOG_NET);
                evt_show_msg("setting: " + m_send_list[num].Substring(0, m_send_list[num].Length - 2) + logLF, MSG_TYPE.LOG_TEST);
                m_tcp.GetStream().BeginRead(m_byte_buf, 0, 256, new AsyncCallback(read_settings_callback), num);
            }
            catch (Exception ex)
            {
                evt_show_msg("send-Error: " + ex.Message + logLF, MSG_TYPE.ERROR_NET);
            }
        }

        void read_settings_callback(IAsyncResult ir)
        {
            int num = (int)ir.AsyncState;
            int ret = m_tcp.GetStream().EndRead(ir);
            if (ret == 0)
            {
                evt_show_msg("read-Error: remote server closen" + logLF, MSG_TYPE.ERROR_NET);
                return;
            }

            string temp_recv = Encoding.ASCII.GetString(m_byte_buf, 0, ret);
            evt_show_msg("read: " + temp_recv + logLF, MSG_TYPE.LOG_NET);

            if (temp_recv.Contains("\r\n"))
            {
                if (!temp_recv.Contains("success"))
                {
                    evt_show_msg("setting-Error: " + temp_recv + logLF, MSG_TYPE.ERROR_SET);
                    return;
                }
            }
            else
            {
                evt_show_msg("setting-unpack-Error: " + temp_recv + logLF, MSG_TYPE.ERROR_SET);
                return;
            }

            num++;
            if (num >= m_send_list.Count)
            {
                evt_show_msg("setting: complete" + logLF, MSG_TYPE.LOG_TEST);
                evt_complete_set(null, null);
                return;
            }

            byte[] b = Encoding.ASCII.GetBytes(m_send_list[num]);
            m_tcp.GetStream().BeginWrite(b, 0, b.Length, new AsyncCallback(write_settings_callback), num);
        }

        void evt_clear_flag()
        {
            m_read_buf = "";
        }

        JcPIMDataResults exec_unpack(string val)
        {
            if (val[0] == '@')
            {
                val = val.Substring(1);
                string[] param = val.Split(',');
                if (param.Length == 9)
                {
                    JcPIMDataResults entry = new JcPIMDataResults();
                    entry.No = Convert.ToInt32(param[0]);
                    entry.P1 = Convert.ToSingle(param[1]);
                    entry.F1 = Convert.ToSingle(param[2]);
                    entry.P2 = Convert.ToSingle(param[3]);
                    entry.F2 = Convert.ToSingle(param[4]);
                    entry.Im_F = Convert.ToSingle(param[5]);
                    entry.Im_V = Convert.ToSingle(param[6]);
                    entry.n1 = Convert.ToInt32(param[7]);
                    entry.n2 = Convert.ToInt32(param[8]);
                    m_pim_resultLists.Add(entry);
                    return entry;
                }
            }
            return null;
        }

        void evt_complete_set(object obj, EventArgs e)
        {
            write_exec();
        }

        void evt_complete_test(object obj, EventArgs e)
        {
            if (m_tcp.Connected)
            {
                m_tcp.GetStream().Close();
            }
            m_tcp.Close();
            evt_show_msg("connect: closen\r\n" + logLF, MSG_TYPE.LOG_NET);

            On_evt_complete_test_handle(obj, e);
        }

        void evt_show_msg(string msg, MSG_TYPE type)
        {
            On_evt_show_log_handle(msg, null);

            if (type == MSG_TYPE.ERROR_NET || type == MSG_TYPE.ERROR_SET || type == MSG_TYPE.ERROR_TEST)
            {
                On_evt_show_error_handle(msg, null);
                evt_complete_test(null, null);
            }
        }

        void evt_update_ui(object obj, EventArgs e)
        {
            On_evt_get_point_handle(obj, e);
        }
    }
}
